From: Aron Xu <aron@debian.org>
Date: Mon, 13 Feb 2012 15:56:51 +0800
Subject: dccp support

---
 nc.1     |    4 ++-
 netcat.c |  111 ++++++++++++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 93 insertions(+), 22 deletions(-)

diff --git a/nc.1 b/nc.1
index 0d92b74..60e3668 100644
--- a/nc.1
+++ b/nc.1
@@ -34,7 +34,7 @@
 .Sh SYNOPSIS
 .Nm nc
 .Bk -words
-.Op Fl 46CDdhklnrStUuvz
+.Op Fl 46CDdhklnrStUuvZz
 .Op Fl I Ar length
 .Op Fl i Ar interval
 .Op Fl O Ar length
@@ -257,6 +257,8 @@ If
 .Ar port
 is not specified, the well-known port for the proxy protocol is used (1080
 for SOCKS, 3128 for HTTPS).
+.It Fl Z
+DCCP mode.
 .It Fl z
 Specifies that
 .Nm
diff --git a/netcat.c b/netcat.c
index eb3453e..56cc15e 100644
--- a/netcat.c
+++ b/netcat.c
@@ -129,6 +129,7 @@ int	rflag;					/* Random ports flag */
 char   *sflag;					/* Source Address */
 int	tflag;					/* Telnet Emulation */
 int	uflag;					/* UDP - Default to TCP */
+int	dccpflag;				/* DCCP - Default to TCP */
 int	vflag;					/* Verbosity */
 int	xflag;					/* Socks proxy */
 int	zflag;					/* Port Scan Flag */
@@ -160,6 +161,7 @@ int	unix_listen(char *);
 void	set_common_sockopts(int);
 int	map_tos(char *, int *);
 void	usage(int);
+char    *proto_name(int uflag, int dccpflag);
 
 static int connect_with_timeout(int fd, const struct sockaddr *sa,
         socklen_t salen, int ctimeout);
@@ -187,7 +189,7 @@ main(int argc, char *argv[])
 	sv = NULL;
 
 	while ((ch = getopt(argc, argv,
-	    "46CDdhI:i:jklnO:P:p:q:rSs:tT:UuV:vw:X:x:z")) != -1) {
+	    "46CDdhI:i:jklnO:P:p:q:rSs:tT:UuV:vw:X:x:Zz")) != -1) {
 		switch (ch) {
 		case '4':
 			family = AF_INET;
@@ -258,6 +260,13 @@ main(int argc, char *argv[])
 		case 'u':
 			uflag = 1;
 			break;
+		case 'Z':
+# if defined(IPPROTO_DCCP) && defined(SOCK_DCCP)
+			dccpflag = 1;
+# else
+			errx(1, "no DCCP support available");
+# endif
+			break;
 		case 'V':
 # if defined(RT_TABLEID_MAX)
 			rtableid = (unsigned int)strtonum(optarg, 0,
@@ -333,6 +342,12 @@ main(int argc, char *argv[])
 
 	/* Cruft to make sure options are clean, and used properly. */
 	if (argv[0] && !argv[1] && family == AF_UNIX) {
+ 		if (uflag)
+ 			errx(1, "cannot use -u and -U");
+# if defined(IPPROTO_DCCP) && defined(SOCK_DCCP)
+		if (dccpflag)
+			errx(1, "cannot use -Z and -U");
+# endif
 		host = argv[0];
 		uport = NULL;
 	} else if (!argv[0] && lflag) {
@@ -374,8 +389,20 @@ main(int argc, char *argv[])
 	if (family != AF_UNIX) {
 		memset(&hints, 0, sizeof(struct addrinfo));
 		hints.ai_family = family;
-		hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
-		hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
+		if (uflag) {
+		    hints.ai_socktype = SOCK_DGRAM;
+		    hints.ai_protocol = IPPROTO_UDP;
+		}
+# if defined(IPPROTO_DCCP) && defined(SOCK_DCCP)
+		else if (dccpflag) {
+		    hints.ai_socktype = SOCK_DCCP;
+		    hints.ai_protocol = IPPROTO_DCCP;
+		}
+# endif
+		else {
+		    hints.ai_socktype = SOCK_STREAM;
+		    hints.ai_protocol = IPPROTO_TCP;
+		}
 		if (nflag)
 			hints.ai_flags |= AI_NUMERICHOST;
 	}
@@ -383,7 +410,10 @@ main(int argc, char *argv[])
 	if (xflag) {
 		if (uflag)
 			errx(1, "no proxy support for UDP mode");
-
+# if defined(IPPROTO_DCCP) && defined(SOCK_DCCP)
+		if (dccpflag)
+			errx(1, "no proxy support for DCCP mode");
+# endif
 		if (lflag)
 			errx(1, "no proxy support for listen");
 
@@ -427,12 +457,12 @@ main(int argc, char *argv[])
 				err(1, NULL);
 
 			char* local;
-			if (family == AF_INET6
+			if (family == AF_INET6 )
 				local = "0.0.0.0";
 			else if (family == AF_INET)
 				local = ":::";
 			else
-				local = "unknown"
+				local = "unknown";
 			fprintf(stderr, "Listening on [%s] (family %d, port %d)\n",
 				host ?: local,
 				family,
@@ -463,12 +493,13 @@ main(int argc, char *argv[])
 				connfd = accept(s, (struct sockaddr *)&cliaddr,
 				    &len);
 				if(vflag) {
+					char *proto = proto_name(uflag, dccpflag);
 				/* Don't look up port if -n. */
 					if (nflag)
 						sv = NULL;
 					else
 						sv = getservbyport(ntohs(atoi(uport)),
-							uflag ? "udp" : "tcp");
+							proto);
 
 					if (((struct sockaddr *)&cliaddr)->sa_family == AF_INET) {
 						char dst[INET_ADDRSTRLEN];
@@ -476,7 +507,7 @@ main(int argc, char *argv[])
 						fprintf(stderr, "Connection from [%s] port %s [%s/%s] accepted (family %d, sport %d)\n",
 							dst,
 							uport,
-							uflag ? "udp" : "tcp",
+							proto,
 							sv ? sv->s_name : "*",
 							((struct sockaddr *)(&cliaddr))->sa_family,
 							ntohs(((struct sockaddr_in *)&cliaddr)->sin_port));
@@ -487,7 +518,7 @@ main(int argc, char *argv[])
 						fprintf(stderr, "Connection from [%s] port %s [%s/%s] accepted (family %d, sport %d)\n",
 							dst,
 							uport,
-							uflag ? "udp" : "tcp",
+							proto,
 							sv ? sv->s_name : "*",
 							((struct sockaddr *)&cliaddr)->sa_family,
 							ntohs(((struct sockaddr_in6 *)&cliaddr)->sin6_port));
@@ -495,7 +526,7 @@ main(int argc, char *argv[])
 					else {
 						fprintf(stderr, "Connection from unknown port %s [%s/%s] accepted (family %d, sport %d)\n",
 							uport,
-							uflag ? "udp" : "tcp",
+							proto,
 							sv ? sv->s_name : "*",
 							((struct sockaddr *)(&cliaddr))->sa_family,
 							ntohs(((struct sockaddr_in *)&cliaddr)->sin_port));
@@ -559,19 +590,20 @@ main(int argc, char *argv[])
 					}
 				}
 
+				char *proto = proto_name(uflag, dccpflag);
 				/* Don't look up port if -n. */
 				if (nflag)
 					sv = NULL;
 				else {
 					sv = getservbyport(
 					    ntohs(atoi(portlist[i])),
-					    uflag ? "udp" : "tcp");
+					    proto);
 				}
 
 				fprintf(stderr,
 				    "Connection to %s %s port [%s/%s] "
 				    "succeeded!\n", host, portlist[i],
-				    uflag ? "udp" : "tcp",
+				    proto,
 				    sv ? sv->s_name : "*");
 			}
 			if (!zflag)
@@ -671,6 +703,24 @@ unix_listen(char *path)
 	return (s);
 }
 
+char *proto_name(uflag, dccpflag) {
+
+    char *proto = NULL;
+    if (uflag) {
+	proto = "udp";
+    }
+# if defined(IPPROTO_DCCP) && defined(SOCK_DCCP)
+    else if (dccpflag) {
+	proto = "dccp";
+    }
+# endif
+    else {
+	proto = "tcp";
+    }
+
+    return proto;
+}
+
 /*
  * remote_connect()
  * Returns a socket connected to a remote host. Properly binds to a local
@@ -709,8 +759,21 @@ remote_connect(const char *host, const char *port, struct addrinfo hints)
 # endif
 			memset(&ahints, 0, sizeof(struct addrinfo));
 			ahints.ai_family = res0->ai_family;
-			ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
-			ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
+			if (uflag) {
+			    ahints.ai_socktype = SOCK_DGRAM;
+			    ahints.ai_protocol = IPPROTO_UDP;
+
+			}
+# if defined(IPPROTO_DCCP) && defined(SOCK_DCCP)
+			else if (dccpflag) {
+			    hints.ai_socktype = SOCK_DCCP;
+			    hints.ai_protocol = IPPROTO_DCCP;
+			}
+# endif
+			else {
+		    	    ahints.ai_socktype = SOCK_STREAM;
+			    ahints.ai_protocol = IPPROTO_TCP;
+			}
 			ahints.ai_flags = AI_PASSIVE;
 			if ((error = getaddrinfo(sflag, pflag, &ahints, &ares)))
 				errx(1, "getaddrinfo: %s", gai_strerror(error));
@@ -722,15 +785,19 @@ remote_connect(const char *host, const char *port, struct addrinfo hints)
 		}
 
 		set_common_sockopts(s);
+		char *proto = proto_name(uflag, dccpflag);
 
-                if ((error = connect_with_timeout(s, res0->ai_addr, res0->ai_addrlen, timeout))== CONNECTION_SUCCESS)
+                if ((error = connect_with_timeout(s, res0->ai_addr, res0->ai_addrlen, timeout))== CONNECTION_SUCCESS) {
 			break;
-		else if (vflag && error == CONNECTION_FAILED)
+		}
+		else if (vflag && error == CONNECTION_FAILED) {
 			warn("connect to %s port %s (%s) failed", host, port,
-			    uflag ? "udp" : "tcp");
-                else if (vflag && error == CONNECTION_TIMEOUT)
+			     proto);
+		}
+                else if (vflag && error == CONNECTION_TIMEOUT) {
                     warn("connect to %s port %s (%s) timed out", host, port,
-                            uflag ? "udp" : "tcp");
+                             proto);
+		}
 
 		close(s);
 		s = -1;
@@ -1047,7 +1114,8 @@ build_ports(char *p)
 	int hi, lo, cp;
 	int x = 0;
 
-        sv = getservbyname(p, uflag ? "udp" : "tcp");
+	char *proto = proto_name(uflag, dccpflag);
+	sv = getservbyname(p, proto);
         if (sv) {
                 portlist[0] = calloc(1, PORT_MAX_LEN);
                 if (portlist[0] == NULL)
@@ -1252,6 +1320,7 @@ help(void)
 	\t-w secs\t	Timeout for connects and final net reads\n\
 	\t-X proto	Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\
 	\t-x addr[:port]\tSpecify proxy address and port\n\
+	\t-Z		DCCP mode\n\
 	\t-z		Zero-I/O mode [used for scanning]\n\
 	Port numbers can be individual or ranges: lo-hi [inclusive]\n");
 	exit(0);
@@ -1261,7 +1330,7 @@ void
 usage(int ret)
 {
 	fprintf(stderr,
-	    "usage: nc [-46CDdhjklnrStUuvz] [-I length] [-i interval] [-O length]\n"
+	    "usage: nc [-46CDdhjklnrStUuvZz] [-I length] [-i interval] [-O length]\n"
 	    "\t  [-P proxy_username] [-p source_port] [-q seconds] [-s source]\n"
 	    "\t  [-T toskeyword] [-V rtable] [-w timeout] [-X proxy_protocol]\n"
 	    "\t  [-x proxy_address[:port]] [destination] [port]\n");
-- 
